//
// Created by huyi on 24-6-15.
//
#pragma once
#include "common.h"

#include <ama.h>
#include <ama_tools.h>

#include <folly/dynamic.h>
#include <folly/logging/xlog.h>

#include <boost/program_options.hpp>

namespace tradev::app {

using amd::ama::Cfg;
using amd::ama::ChannelMode;
using amd::ama::ErrorCode;
using amd::ama::IAMDApi;
using amd::ama::LogLevel;
using amd::ama::MDFutureSnapshot;
using amd::ama::MDIndexSnapshot;
using amd::ama::MDOptionSnapshot;
using amd::ama::MDSnapshot;
using amd::ama::SubscribeDataType;
using amd::ama::SubscribeType;

static constexpr auto* kZeroIp = "0.0.0.0";

struct ItemType : public folly::MoveOnly {
  ItemTypes type;
  // 联合体节省内存
  union {
    MDSnapshot*       stocks;
    MDOptionSnapshot* options;
    MDIndexSnapshot*  indexes;
    MDFutureSnapshot* futures;
  };
  size_t   size;
  uint64_t timestamp{0};

  ItemType(ItemTypes type, void* snapshot, size_t size)
      : type(type)
      , size(size) {
    switch (type) {
    case kMdSnapshot:
      stocks = (MDSnapshot*)snapshot;
      break;
    case kMdOptionSnapshot:
      options = (MDOptionSnapshot*)snapshot;
      break;
    case kMdIndexSnapshot:
      indexes = (MDIndexSnapshot*)snapshot;
      break;
    case kMdFutureSnapshot:
      futures = (MDFutureSnapshot*)snapshot;
      break;
    case kStopped:
      break;
    default:
      throw std::runtime_error(fmt::format("Invalid item type {}", (int)type));
    }
  }

  ~ItemType() {
    // type是kStopped时直接退出
    if (type == kStopped) {
      return;
    }

    // 根据type来释放内存
    if (stocks != nullptr && type == kMdSnapshot) {
      IAMDApi::FreeMemory((MDSnapshot*)stocks);
    } else if (options != nullptr && type == kMdOptionSnapshot) {
      IAMDApi::FreeMemory((MDOptionSnapshot*)options);
    } else if (indexes != nullptr && type == kMdIndexSnapshot) {
      IAMDApi::FreeMemory((MDIndexSnapshot*)indexes);
    } else if (futures != nullptr && type == kMdFutureSnapshot) {
      IAMDApi::FreeMemory((MDFutureSnapshot*)futures);
    }
  }
};

using ItemPtr   = std::unique_ptr<ItemType>;
using QueueType = folly::ProducerConsumerQueue<ItemPtr>;

class AmaInstance : public amd::ama::IAMDSpi {
private:
  std::atomic_bool _closed{false};
  Options          _options;
  Args             _args;
  QueueType*       _queue;
  std::uint64_t    _recv_md_count; /* 接收到的快照个数 */

public:
  AmaInstance(folly::dynamic options, Args args, QueueType* q)
      : _options(std::move(options))
      , _args(std::move(args))
      , _queue(q)
      , _recv_md_count(0) {}

  ~AmaInstance() override {
    close();
  }

  FOLLY_NODISCARD bool isAvaliable() const { return !_closed; }

  int open();

  void OnLog(const int32_t& level, const char* log, uint32_t len) override {
    switch (level) {
    case LogLevel::kTrace: XLOG(DBG) << log; break;
    case LogLevel::kDebug: XLOG(DBG0) << log; break;
    case LogLevel::kInfo: XLOG(INFO) << log; break;
    case LogLevel::kWarn: XLOG(WARN) << log; break;
    case LogLevel::kError: XLOG(ERR) << log; break;
    case LogLevel::kFatal: XLOG(FATAL) << log; break;
    default: break;
    }
  }

  void OnEvent(uint32_t level, uint32_t code, const char* log, uint32_t len) override {
    switch (level) {
    case LogLevel::kTrace: XLOG(DBG) << code << " " << log; break;
    case LogLevel::kDebug: XLOG(DBG0) << code << " " << log; break;
    case LogLevel::kInfo: XLOG(INFO) << code << " " << log; break;
    case LogLevel::kWarn: XLOG(WARN) << code << " " << log; break;
    case LogLevel::kError: XLOG(ERR) << code << " " << log; break;
    case LogLevel::kFatal: XLOG(FATAL) << code << " " << log; break;
    default: break;
    }
  }

  void initSnapshot(ItemType& ctx);
  void OnMDSnapshot(MDSnapshot* snapshots, uint32_t cnt) override;
  void OnMDOptionSnapshot(MDOptionSnapshot* snapshots, uint32_t cnt) override;
  void OnMDIndexSnapshot(MDIndexSnapshot* snapshots, uint32_t cnt) override;
  void OnMDFutureSnapshot(MDFutureSnapshot* snapshots, uint32_t cnt) override;

  void close();
};

} // namespace tradev::app
